/*
     Copyright 2007 Joseph M. Ferner

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

using System;
using System.Collections.Generic;
using System.IO;

namespace OpenServers.Net.Common.Utils {
    /// <summary>
    /// A stream composed of multiple streams in order. Reads from this stream will read from each
    /// stream in order until all streams are read from.
    /// </summary>
    public class CompositeStream : Stream {
        private long _position = 0;
        private readonly IList<Stream> _streams = new List<Stream>();

        /// <summary>
        /// Not Implemented.
        /// </summary>
        public override void Flush() {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Not Implemented.
        /// </summary>
        public override long Seek(long offset, SeekOrigin origin) {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Not Implemented.
        /// </summary>
        public override void SetLength(long value) {
            throw new NotImplementedException();
        }

        ///<summary>
        ///When overridden in a derived class, reads a sequence of bytes from the current stream and advances the position within the stream by the number of bytes read.
        ///</summary>
        ///
        ///<returns>
        ///The total number of bytes read into the buffer. This can be less than the number of bytes requested if that many bytes are not currently available, or zero (0) if the end of the stream has been reached.
        ///</returns>
        ///
        ///<param name="offset">The zero-based byte offset in buffer at which to begin storing the data read from the current stream. </param>
        ///<param name="count">The maximum number of bytes to be read from the current stream. </param>
        ///<param name="buffer">An array of bytes. When this method returns, the buffer contains the specified byte array with the values between offset and (offset + count - 1) replaced by the bytes read from the current source. </param>
        ///<exception cref="T:System.ArgumentException">The sum of offset and count is larger than the buffer length. </exception>
        ///<exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exception>
        ///<exception cref="T:System.NotSupportedException">The stream does not support reading. </exception>
        ///<exception cref="T:System.ArgumentNullException">buffer is null. </exception>
        ///<exception cref="T:System.IO.IOException">An I/O error occurs. </exception>
        ///<exception cref="T:System.ArgumentOutOfRangeException">offset or count is negative. </exception><filterpriority>1</filterpriority>
        public override int Read(byte[] buffer, int offset, int count) {
            int result = 0;
            while (_streams.Count > 0 && count > 0) {
                int read = _streams[0].Read(buffer, offset, count);
                _position += read;
                if (read != 0) {
                    result += read;
                    offset += read;
                    count -= read;
                } else {
                    _streams[0].Close();
                    _streams.RemoveAt(0);
                }
            }
            return result;
        }

        /// <summary>
        /// Not Implemented.
        /// </summary>
        public override void Write(byte[] buffer, int offset, int count) {
            throw new NotImplementedException();
        }

        ///<summary>
        ///When overridden in a derived class, gets a value indicating whether the current stream supports reading.
        ///</summary>
        ///
        ///<returns>
        ///true if the stream supports reading; otherwise, false.
        ///</returns>
        ///<filterpriority>1</filterpriority>
        public override bool CanRead {
            get { return true; }
        }

        ///<summary>
        ///When overridden in a derived class, gets a value indicating whether the current stream supports seeking.
        ///</summary>
        ///
        ///<returns>
        ///true.
        ///</returns>
        ///<filterpriority>1</filterpriority>
        public override bool CanSeek {
            get { return false; }
        }

        ///<summary>
        ///When overridden in a derived class, gets a value indicating whether the current stream supports writing.
        ///</summary>
        ///
        ///<returns>
        ///false.
        ///</returns>
        ///<filterpriority>1</filterpriority>
        public override bool CanWrite {
            get { return false; }
        }

        /// <summary>
        /// Returns the length of all the streams added together.
        /// </summary>
        public override long Length {
            get {
                long result = 0;
                foreach (Stream stream in _streams) {
                    result += stream.Length;
                }
                return result;
            }
        }

        /// <summary>
        /// gets the position from the begging of the stream.  Cannot be set.
        /// </summary>
        public override long Position {
            get { return _position; }
            set { throw new NotImplementedException(); }
        }

        ///<summary>
        /// Adds a stream to be read from.
        ///</summary>
        public void Add(Stream stream) {
            _streams.Add(stream);
        }
    }
}
